package controller;
import game.ClassicChess;
import game.EightQueens;
import game.GameState;
import game.GameType;
import game.KnightTour;
import game.GameStateListener;

import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import javax.swing.JOptionPane;

import view.*;

/**
 * The player class for each of the gameTypes that can be implemented.
 * 
 * @author Nicole Waldrum
 * @date January 30, 2010
 * @version 1.0
 * 
 * @author Trevor Bastian
 * @date February 22, 2010
 * @version 2.0
 * 
 * @author Mark Kelly
 * @date February 24, 2010
 * @version 2.0
 *
 */
public class ChessController extends MouseAdapter implements ActionListener {
	public GameState gameState;
	private GameStateListener gsl;
	/**
	 * Creates a new instance of player, should the player be playing chess there will be two players.
	 * @param current, the current place a piece is located
	 * @param future, the future place the user would like the piece located
	 */
	public ChessController(GameStateListener gsl) {
		this.gsl = gsl;
	}

	/**
	 * Takes in two points in string format 'char int' and changes them into points, checks if they're valid and passes them
	 * on to gameState.
	 * 
	 * @param current location of piece to move
	 * @param future desired location
	 * @return true if its a valid move
	 */
	public boolean parseMove (String current, String future) {
		int CCurrent;
		int RCurrent;
		int CFuture;
		int RFuture;
		
		if (current == null || future == null || current.length() != 2 || future.length() != 2) {
			return false;
		}
		
		//changes the values to uppercase
		current = current.toUpperCase();
		future = future.toUpperCase();

		//changes the variables to ascii
		CCurrent = (int)(current.charAt(0) - 'A') + 1;
		CFuture = (int)(future.charAt(0) - 'A') + 1;
		RCurrent = (int)current.charAt(1) - '0';
		RFuture = (int)future.charAt(1) - '0';
		
		if (CCurrent > 8 || CCurrent < 1 || CFuture > 8 || CFuture < 1 ||
				RCurrent > 8 || RCurrent < 1 || RFuture > 8 || RFuture < 1) {
			return false;
		}

		return gameState.getGameType().movePiece(new Point (CCurrent, RCurrent), new Point(CFuture, RFuture));
	}
	
	/**
	 * Returns the board in string format
	 * 
	 * @return a string representation of the board
	 */
	public String boardString() {
		return gameState.getBoard().toString();
	}
	
	/**
	 * checks if the player have clicked a specific point on the board to move a piece.
	 * @param arg0 checks if the player has clicked on the board in anyway
	 */
	public void mouseClicked(MouseEvent arg0) {
	}

	@Override
	public void actionPerformed(ActionEvent event) {		
		String command = event.getActionCommand();
		
		if (command == "Exit"){
			System.exit(0);
		}
		else if(command == "Chess"){
			startGame(ClassicChess.class, gsl);
		}
		else if(command == "Knight's Tour"){
			startGame(KnightTour.class, gsl);
		}
		else if (command == "8 Queen's Problem"){
			startGame(EightQueens.class, gsl);
		}
		else if(command == "Move"){
			new PlayerGUI(this);
		}
		else if (command == "Help") {
			// TODO call ChessGUI.showHelp() through interface
			JOptionPane.showMessageDialog(null, "Please only enter a letter and a number to move.", "How to Move Pieces", JOptionPane.OK_OPTION);
		}
		else {
			JOptionPane pane = new JOptionPane();
			pane.setSize(50, 10);
			JOptionPane.showMessageDialog(pane, "Invalid selection.");
		}
	}

	/**
	 * Starts a game of the specified type.
	 * 
	 * @param <T> they type of game
	 * @param clazz a class representing the type of game
	 */
	private <T extends GameType> void startGame(Class<T> clazz, GameStateListener... gsl) {
		Constructor<T> constructor = null;
		GameType g = null;
		
		try {
			constructor = clazz.getConstructor(); // retrieve the constructor
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
		
		try {
			g = constructor.newInstance(); // invoke the constructor
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		
		gameState = new GameState(g);
		g.setGameState(gameState);
		
		for (GameStateListener p : gsl) {
			gameState.addGameStateListener(p);
		}
		
		JOptionPane.showMessageDialog(null, "Due to a bug, currently you have to move a piece to get the GUI to show. We recommend something in row 2 to row 3 or row 4");
	}
}
